use std::marker::PhantomData;

struct OrderCompleted;
struct InCompleteOrder;
struct ItemProvided;
struct NoItem;
struct AddressProvided;
struct NoAddress;

struct Order<A, B, C>{
    itemId: Option<String>,
    shippingAddress: Option<String>,
    _a:PhantomData<A>,
    _b:PhantomData<B>,
    _c:PhantomData<C>
}
impl<A, B, C> Order<A, B, C> {
    fn emptyOrder() -> Order<InCompleteOrder, NoItem, NoAddress>{
        Order {
            itemId: None,
            shippingAddress: None,
            _a:PhantomData,
            _b:PhantomData,
            _c:PhantomData
        }
    }
}

mod OrderingSystem{
    use super::*;

    fn add_item<A, B>(item: String, o: Order<A, NoItem, B>) ->  Order<A, ItemProvided, B>{
        Order {
            itemId: Some(item),
            shippingAddress: o.shippingAddress,
            _a:PhantomData,
            _b:PhantomData,
            _c:PhantomData
        }
    }

    fn add_shipping<A, B>(address: String, o: Order<A, B, NoAddress>) -> Order<A, B, AddressProvided> {
        Order {
            itemId: o.itemId,
            shippingAddress: Some(address),
            _a:PhantomData,
            _b:PhantomData,
            _c:PhantomData
        }
    }

    fn place_order(o: Order<InCompleteOrder, ItemProvided, AddressProvided>) -> Order<OrderCompleted, ItemProvided, AddressProvided> {
        Order {
            itemId: o.itemId,
            shippingAddress: o.shippingAddress,
            _a:PhantomData,
            _b:PhantomData,
            _c:PhantomData
        }
    }

}


// object OrderingSystem {
// def addItem[A, B](item: String, o: Order[A, NoItem, B]): Order[A, ItemProvided, B] = {
// o.copy[A, ItemProvided, B](itemId = Some(item))
// }
// def addShipping[A, B](address: String, o: Order[A, B, NoAddress]): Order[A, B, AddressProvided] =
// o.copy[A, B, AddressProvided](shippingAddress = Some(address))
// def placeOrder (o: Order[InCompleteOrder, ItemProvided, AddressProvided]): Order[OrderCompleted, ItemProvided, AddressProvided] =
// o.copy[OrderCompleted, ItemProvided, AddressProvided]()
// }
